const proto_tools = require(`proto_tools`);
/* 规定
- 服务号，命令号不能为0
- 服务号与命令号大小不能超过2个字节的整数；
- buf协议里面2个字节存放服务号（0开始的2个字节），命令号（1开始的2个字节），
- 加密,解密
- 服务号和命令号二进制中都用小尾
- 所有文本都用utf8
*/

let log = {
    info: console.log,
    warn: console.warn,
    error: console.error
}
const proto_man = {
    PROTO_JSON: 1,
    PROTO_BUF: 2,
    encode_cmd: encode_cmd,
    decode_cmd: decode_cmd,
    reg_buf_decoder: reg_buf_decoder,
    reg_buf_encoder: reg_buf_encoder,
};

/** 数据加密 */
function encrypt_cmd(cmd) {
    return cmd;
}

/** 数据解密 */
function decrypt_cmd(encmd) {
    return encmd;
}

function _json_encode(stype, ctype, body) {
    let cmd = {};
    cmd[0] = body;
    
    let str = JSON.stringify(cmd);
    let cmd_buf = proto_tools.encode_str_cmd(stype, ctype, str);
    return cmd_buf;
}

function _json_decode(cmd_buf) {
    let cmd = proto_tools.decode_str_cmd(cmd_buf);
    let cmd_json = cmd[2];
    try{
        let body_set = JSON.parse(cmd_json);
        cmd[2] = body_set[0];
    }catch(e){
        return null;
    }
    if (!cmd
        || typeof (cmd[0]) === `undefined`
        || typeof (cmd[1]) === `undefined`
        || typeof (cmd[2]) === `undefined`) {
        return null;
    }

    return cmd;
}
/** buf协议的编码/解码管理 stype, ctype -> encoder / decoder */
const decoders = {}; // 保存buf协议所有解码函数
const encoders = {}; // 保存buf协议所有编码函数

/** stype + ctype -> key */
function get_key(stype, ctype) {
    return (stype * 65536 + ctype);
}

/**
 * 
 * @param {*} proto_type 协议类型
 * @param {*} stype 服务号
 * @param {*} ctype 命令号
 * @param {*} body 数据本体
 * @requires 编码后的一段数
 */
function encode_cmd(proto_type, stype, ctype, body) {
    let buf = null;
    let dataview;
    /** json编码 */
    if (proto_type == proto_man.PROTO_JSON) {
        dataview = _json_encode(stype, ctype, body);
    } else {
        /** buf */
        let key = get_key(stype, ctype);
        if (!encoders[key]) {
            return null;
        }
        // buf = encoders[key](stype, ctype, body);
        dataview = encoders[key](stype, ctype, body);
    }
    proto_tools.write_prototype_inbuf(dataview, proto_type);
    buf = dataview.buffer;
    if (buf){
        buf = encrypt_cmd(buf); //加密
    }
    return buf;
}

/**
 * 
 * @param {*} proto_type 协议类型
 * @param {*} str_of_buf_cmd 接收到的数据命令
 * @returns  cmd: {0: stype, 1: ctype, 2: body}
 */
function decode_cmd(proto_type, str_or_buf) {
    str_or_buf = decrypt_cmd(str_or_buf); //解密
    let cmd = null;
    let dataview = new DataView(str_or_buf);
    if(dataview.byteLength < proto_tools.header_size){
        return null;
    }
    if (proto_type == proto_man.PROTO_JSON) {
        return _json_decode(dataview);
    }
    // if(str_or_buf.length < 4){
    //     return null;
    // }

    let stype = proto_tools.read_int16(dataview, 0);
    let ctype = proto_tools.read_int16(dataview, 2);
    let key = get_key(stype, ctype);
    if (!decoders[key]) {
        return null;
    }
    // cmd = decoders[key](str_or_buf);
    cmd = decoders[key](dataview);
    return cmd;
}

/**
 * 
 * @param {*} stype 
 * @param {*} ctype 
 * @param {*} encode_func (body) return 二进制buffer对象
 */
function reg_buf_encoder(stype, ctype, encode_func) {
    let key = get_key(stype, ctype);
    if (encoders[key]) { //已经注册过了
        log.warn(`stype: ${stype} ctype: ${ctype} is register`);
    }
    encoders[key] = encode_func;
}

/**
 * 
 * @param {*} stype 
 * @param {*} ctype 
 * @param {*} decode_func (cmd_buf) return cmd {0: 服务号，1: 命令号 2: body}
 */
function reg_buf_decoder(stype, ctype, decode_func) {
    let key = get_key(stype, ctype);
    if (decoders[key]) { //已经注册过了
        log.warn(`stype: ${stype} ctype: ${ctype} is register`);
    }
    decoders[key] = decode_func;
}

module.exports = proto_man;